package week7.day43;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Set;

/**
 * @Author 远志 zhangsong@cskaoyan.onaliyun.com
 * @Date 2024/5/27 15:53
 * @Version 1.0
 */
public class MainServer4 {

    public static void main(String[] args) {
        // 要求：去实现一个服务器，可以将本地的资源发布到网络中，供网络上面的其他用户来访问
        // 创建一个程序，持续不断地去监听位于8080端口号上面的请求信息
        try {
            ServerSocket serverSocket = new ServerSocket(8080);
            // 这一行代码默认情况下在没有客户端连接进来时是阻塞的；每当有一个客户端连接进来，那么调用一次
            // 这里面的client是什么？？？？其实就是和当前的服务器建立连接的客户端信息
            // 只要建立一个tcp连接，那么便会有一个socket
            while (true){
                // 阻塞
                Socket client = serverSocket.accept();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // 所以，如果需要获取客户端的发送过来的请求信息，或者需要给客户端返回响应信息，都需要借助于client来进行处理
                        InputStream inputStream = null;
                        try {
                            // 往bytes数组里面去写入数据。写入的长度是length
                            // 此处也是阻塞的，如果没有接收到客户端的请求信息，会阻塞一段时间，最终返回-1
                            Request request = new Request(client);
                            String uri = request.getUri();
                            String method = request.getMethod();
                            String protocol = request.getProtocol();
                            System.out.println(uri + " " + method + " " + protocol);
                           Set<String> headerNames =  request.getHeaderNames();
                           for (String headerName : headerNames) {
                               String value = request.getHeader(headerName);
                               System.out.println("value = " + value);
                           }
                            String referer = request.getHeader("Referer");
                            // 此时已经获取到了客户端的连接信息，需要做的事情便是获取客户端的真实意图，做出正确的响应
                            // 获取请求资源：通过观察请求报文可以发现，请求行是一个单独的行；每一个请求头独占一行；可以利用换行来分割出请求行
                            // 再次利用空格来分割三个部分：请求方法 请求资源 版本协议
                            // 需要找到换行符的index下标
                            // 做出正确的响应？？？如果文件存在，则响应出去；如果文件不存在，则返回404状态码
                            // 希望给客户端返回响应信息
                            // 我们这里面采取一种比较简单理想的方式，就是在当前应用根目录下去查找文件
                            // 对于uri需要处理一下，为什么呢？因为它是以/开头，会被当做linux里面的绝对路径去看待  /usr/local
                            File file = new File(uri.substring(1));
                            OutputStream outputStream = client.getOutputStream();
                            // 需要去构建响应报文
                            StringBuffer stringBuffer = new StringBuffer();
                            if(file.exists() && file.isFile()){
                                stringBuffer.append("HTTP/1.1 200 OK\r\n");
                                stringBuffer.append("Content-Type:text/html\r\n");
                                stringBuffer.append("\r\n");
                                // 把响应行、响应头、空行部分响应出去
                                outputStream.write(stringBuffer.toString().getBytes("utf-8"));
                                // 存在并且不是目录，是文件，，，，应当把它响应出去
                                FileInputStream fileInputStream = new FileInputStream(file);
                                int read = 0;
                                byte[] buffer = new byte[1024];
                                while ((read = fileInputStream.read(buffer)) != -1){
                                    // 这里面就是在输出响应体
                                    outputStream.write(buffer, 0, read);
                                }
                            }else {
                                stringBuffer.append("HTTP/1.1 404 File Not Found\r\n");
                                stringBuffer.append("Content-Type:text/html\r\n");
                                stringBuffer.append("\r\n");
                                stringBuffer.append("<div style='color:red'>File Not Found</div>");
                                outputStream.write(stringBuffer.toString().getBytes("utf-8"));
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }finally {
                            try {
                                client.close();
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }

                        }


                    }
                }).start();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}
